package mr.go.set.tests;

import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import mr.go.set.AggregatedSet;
import mr.go.set.Predicate;

final class Helpers {

	public static final Predicate<Integer> counterEq10 = new Predicate<Integer>() {

		@Override
		public boolean evaluate(Integer value) {
			return value == 10;
		}
	};

	public static final Predicate<Integer> counterGt10 = new Predicate<Integer>() {

		@Override
		public boolean evaluate(Integer value) {
			return value > 10;
		}
	};;

	public static final Predicate<Integer> counterLeq10 = new Predicate<Integer>() {

		@Override
		public boolean evaluate(Integer value) {
			return value <= 10;
		}
	};;

	public static final Condition never = new Condition() {

		@Override
		public boolean isTrue() {
			return false;
		}

	};

	public static Runnable increaseCountOfAllElementsByOne(final Set<String> set) {
		return new Runnable() {

			@Override
			public void run() {
				for (String line : set) {
					set.add(line);
				}
			}
		};
	}

	public static Future<?>[] startThreads(ExecutorService executor, int n,
			final Runnable whatToDo, final Condition stopCondition,
			final Condition signalCondition, final Signal signal) {
		Future<?>[] result = new Future[n];
		for (int i = 0; i < n; i++) {
			result[i] = executor.submit(new Runnable() {

				@Override
				public void run() {
					while (!stopCondition.isTrue()) {
						whatToDo.run();
						if (signalCondition.isTrue())
							signal.signal();
					}
				}
			});
		}
		return result;
	}

	public static Condition stopAfterNtimes(final int n) {
		return new Condition() {

			private int current;

			private int times;
			{
				times = n;
				current = 0;
			}

			@Override
			public boolean isTrue() {
				return ++current >= times;
			}
		};
	}

	public static final Condition stopWhenEmpty(final Set<?> set) {
		return new Condition() {

			@Override
			public boolean isTrue() {
				return set.isEmpty();
			}
		};
	}

	public static Condition stopWhenExists(final AggregatedSet<?, Integer> set,
			final Predicate<Integer> condition) {
		return new Condition() {

			@Override
			public boolean isTrue() {
				return !set.allSatisfyingStrict(condition).isEmpty();
			}
		};
	}

	public static void waitFor(Future<?>[] futures)
			throws InterruptedException, AssertionError, ExecutionException {
		try {
			futures[0].get();
			futures[1].get();
		} catch (ExecutionException e) {
			if (e.getCause() instanceof AssertionError)
				throw (AssertionError) e.getCause();
			throw e;
		}
	}
}
